package controls

import (
	"github.com/labstack/echo/v4"
	"github.com/rs/xid"
	"io"
	"os"
	"sofuny/models"
	"sofuny/utils"
	"strconv"
	"strings"
	"time"
)

// 文件上传
func TransferFile(ctx echo.Context) error {
	var transfer models.TransferFile
	// 获取上传文件名
	file, err := ctx.FormFile("file")
	if err != nil {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "获取数据失败",
			Data:  err,
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	fileRead, err := file.Open()
	if err != nil {
		return ctx.JSON(200, utils.Response{
			Code: 201,
			Msg:  "打开文件失败",
			Data: err.Error(),
			Time: utils.FormatTime(),
		})
	}
	defer fileRead.Close()
	// 根据uuid 生成图片名称
	fileNames := strings.Split(file.Filename, ".")
	var fileType string
	// 判断文件类型
	switch fileNames[len(fileNames)-1] {
	case "jpeg":
		fileType = "image/jpeg"
		break
	case "jpg":
		fileType = "image/jpeg"
		break
	case "gif":
		fileType = "image/gif"
		break
	case "png":
		fileType = "image/png"
		break
	case "webp":
		fileType = "image/webp"
		break
	case "mp4":
		fileType = "video/mpeg4"
		break
	case "mp3":
		fileType = "audio/mp3"
		break
	case "json":
		fileType = "application/json"
		break
	case "pdf":
		fileType = "application/pdf"
		break
	case "html":
		fileType = "text/html"
		break
	case "xml":
		fileType = "text/xml"
		break
	case "apk":
		fileType = "application/vnd.android.package-archive"
		break
	case "avi":
		fileType = "video/avi"
		break
	case "class":
		fileType = "java/*"
		break
	case "crt":
		fileType = "application/x-x509-ca-cert"
		break
	case "css":
		fileType = "text/css"
		break
	case "js":
		fileType = "application/x-javascript"
		break
	case "svg":
		fileType = "text/xml"
		break
	default:
		fileType = "application/octet-stream"
		break
	}

	imgName := xid.New().String() + "." + fileNames[len(fileNames)-1]
	// 创建 文件 路径
	dist, err := os.Create("./static/transfer/" + imgName)
	if err != nil {
		return ctx.JSON(200, utils.Response{
			Code: 201,
			Msg:  "创建文件路径失败",
			Data: err.Error(),
			Time: utils.FormatTime(),
		})
	}
	defer dist.Close()
	// 复制 内容到文件
	if _, err = io.Copy(dist, fileRead); err != nil {
		return ctx.JSON(200, utils.Response{
			Code: 201,
			Msg:  "复制打开文件的内容失败",
			Data: err.Error(),
			Time: utils.FormatTime(),
		})
	}

	// 上传成功 写入数据库　生成取件码　文件过期时间
	transfer.CreateAt = time.Now().Local()
	transfer.UpdateAt = transfer.CreateAt
	transfer.Status = true
	transfer.Uuid = xid.New().String()

	transfer.Name = file.Filename
	transfer.Size = file.Size
	transfer.Type = fileType
	transfer.Url = app.StaticApi + "/static/transfer/" + imgName

	transfer.NickName = imgName
	// 下次次数
	transfer.DownloadCounts = 0

	PickupCode := utils.SixCaptcha()

	// TODO 只做了简单判断 无法保证唯一性
	if JudgePickupCode(PickupCode) {
		PickupCode = utils.SixCaptcha()
	}
	//
	transfer.PickupCode = PickupCode
	// 设置过期时间 24小时内有效
	transfer.ExpireDate = time.Now().Local().Add(time.Hour * 24)

	// 创建　快传文件
	if err := db.Create(&transfer).Error; err != nil {
		// 创建失败　删除文件
		// 获取当前路径
		pwdPath, _ := os.Getwd()
		// 执行移除图片
		_ = os.Remove(pwdPath + "/static/transfer/" + imgName)

		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "创建快传文件失败",
			Data:  err,
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// TODO 快传文件统计
	//utils.SendMailBySendCloud(
	//	app.Email,
	//	app.Name+" | 消息通知",
	//	"<h2>hi,管理员:</h2></p>有人上传文件的快传地址了，快去查看吧</p>")
	// 返回　取件码
	return ctx.JSON(200, utils.Response{
		Code:  200,
		Msg:   "success",
		Data:  PickupCode,
		Total: 1,
		Time:  utils.FormatTime(),
	})
}

// 判断取件码
func JudgePickupCode(code string) bool {
	// TODO 取件码要不一样 查询取件码是否存在 不能保证新的取件码是否唯一
	var tf models.TransferFile
	if err := db.Limit(1).Where("pickup_code=?", code).Find(&tf).Error; err != nil {
		return false
	}
	return true
}

// 获取
func GetTransferFile(ctx echo.Context) error {
	var transfer models.TransferFile
	code := ctx.QueryParam("code")
	// 判断数据
	if code == "" {
		// 返回　取件码
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   utils.DataEmptyMessage,
			Data:  nil,
			Total: 0,
			Time:  utils.FormatTime(),
		})
	}
	//查找
	if err := db.Where("status=? and pickup_code=?", true, code).Find(&transfer).Error; err != nil {
		// 返回　取件码
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "文件不存在或已过期",
			Data:  err.Error(),
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// 判断是否过期 当前日期大于快传文件过期日期
	if time.Now().Local().Unix() >= transfer.ExpireDate.Unix() {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "文件已过期",
			Data:  nil,
			Total: 0,
			Time:  utils.FormatTime(),
		})
	}
	// 返回　下载地址
	return ctx.JSON(200, utils.Response{
		Code:  200,
		Msg:   "success",
		Data: map[string]string{
			"downloadUrl": transfer.Url,
			"expireDate": transfer.ExpireDate.Format("2006-01-02 15:04:05"),
			"downloadCounts": strconv.Itoa(transfer.DownloadCounts),
			"nickName": transfer.NickName,
			"name": transfer.Name,
		},
		Total: 1,
		Time:  utils.FormatTime(),
	})
}

// 下载文件
func DownloadFile(ctx echo.Context) error {
	var transfer  models.TransferFile
	// 获取当前路径
	pwdPath, _ := os.Getwd()
	name := ctx.QueryParam("name")
	if err := db.Where("nick_name=?", name).Find(&transfer).Error; err != nil {
		//return ctx.JSON(200, "下载失败")
		return err
	}
	if err := db.Model(&transfer).Where("nick_name=?", name).Update("download_counts", transfer.DownloadCounts+1).Error; err != nil {
		//return ctx.JSON(200, "下载失败")
		return err
	}
	file, err := os.Open(pwdPath+"/static/transfer/"+name)
	if err != nil {
		return err
	}
	return ctx.Stream(200, transfer.Type, file)
}

// 定时清除过期文件
func ClearOutdatedFiles() {
	var transfers []models.TransferFile
	if err := db.Find(&transfers).Error; err != nil {
		//fmt.Println("获取快传文件失败")
	}
	// 判断
	for _, item := range transfers {
		// 过期
		if item.ExpireDate.Unix() <= time.Now().Local().Unix() {
			if err := db.Model(&item).Where("id=?", item.ID).Update("status", false).Error; err != nil {
				//fmt.Println("删除失败!=>", err.Error())
			} else {
				// 过期文件　处理
				pwdPath, _ := os.Getwd()
				// 执行移除文件
				_ = os.Remove(pwdPath + "/static/transfer/" + item.NickName)
			}
		} else {
			// 没过期
			//fmt.Println("没过期", item.ID)
		}
	}
}


// 后台
// 所有
func AdminFindAllTransferFile(ctx echo.Context) error {
	var transfers []models.TransferFile
	// 查找
	if err := db.Order("create_at desc").Find(&transfers).Error; err != nil {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "查找快传失败",
			Data:  err,
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// 返回
	return ctx.JSON(200, utils.Response{
		Code:  200,
		Msg:   "success",
		Data:  transfers,
		Total: len(transfers),
		Time:  utils.FormatTime(),
	})
}

// 添加
func AdminAddTransferFile(ctx echo.Context) error {
	return nil
}

// 修改
func AdminChangeTransferFile(ctx echo.Context) error {
	return nil
}

// 删除
func AdminDeleteTransferFile(ctx echo.Context) error {
	var v utils.Value
	var transfer models.TransferFile
	// 数据绑定
	if err := ctx.Bind(&v); err != nil {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   utils.DataBindErrorMessage,
			Data:  err.Error(),
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// 判断数据
	if v.Uuid == "" {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "uuid不允许为空",
			Data:  nil,
			Total: 0,
			Time:  utils.FormatTime(),
		})
	}
	// 查找句子
	if err := db.Where("uuid=?", v.Uuid).Find(&transfer).Error; err != nil {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "获取快传失败",
			Data:  err.Error(),
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// 执行删除
	if err := db.Unscoped().Delete(&transfer).Error; err != nil {
		return ctx.JSON(200, utils.Response{
			Code:  201,
			Msg:   "删除快传失败",
			Data:  err.Error(),
			Total: 1,
			Time:  utils.FormatTime(),
		})
	}
	// 删除成功
	return ctx.JSON(200, utils.Response{
		Code:  200,
		Msg:   "删除成功!",
		Data:  nil,
		Total: 0,
		Time:  utils.FormatTime(),
	})
}

